/**
 * XDevice Raft测试通用辅助函数库
 * 
 * 提供所有Raft测试文件共用的辅助函数和结构体定义
 */

#include <xdevice/xdevice.h>
#include <xdevice/raft.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <assert.h>
#include <signal.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <math.h>

#ifndef XDEVICE_TEST_HELPERS_H
#define XDEVICE_TEST_HELPERS_H

/* ========== 测试配置常量 ========== */
#define MAX_TEST_NODES 7
#define TEST_TIMEOUT_MS 10000
#define HEARTBEAT_INTERVAL_MS 50
#define ELECTION_TIMEOUT_MS 300

/* ========== 测试节点结构 ========== */
typedef struct {
    int node_id;
    xdevice_context_t* ctx;
    pthread_t worker_thread;
    bool running;
    bool crashed;
    bool isolated;
    
    uint64_t current_term;
    int voted_for;
    xdevice_node_state_t state;
    uint64_t commit_index;
    uint64_t last_applied;
    
    uint64_t messages_sent;
    uint64_t messages_received;
    uint64_t elections_started;
    uint64_t leadership_terms;
    
    pthread_mutex_t lock;
} test_node_t;

/* ========== 网络模拟器结构 ========== */
typedef struct {
    bool connected[MAX_TEST_NODES][MAX_TEST_NODES];
    int message_delay_ms[MAX_TEST_NODES][MAX_TEST_NODES];
    double packet_loss_rate[MAX_TEST_NODES][MAX_TEST_NODES];
    pthread_mutex_t lock;
} network_simulator_t;

/* ========== 测试环境结构 ========== */
typedef struct {
    test_node_t nodes[MAX_TEST_NODES];
    int node_count;
    network_simulator_t network;
    
    int current_leader;
    uint64_t global_term;
    uint64_t global_commit_index;
    bool test_running;
    
    pthread_mutex_t env_lock;
    pthread_cond_t state_changed;
    
    uint64_t total_operations;
    uint64_t successful_operations;
    uint64_t failed_operations;
    uint64_t leader_changes;
    double start_time;
} test_environment_t;

/* ========== Global Variables ========== */
test_environment_t g_test_env = {0};

/* ========== Function Declarations ========== */

/* Time related */
double get_current_time_ms(void);
void sleep_ms(int ms);

/* 日志记录 */
void log_test_info(const char* level, const char* format, ...);
#define LOG_INFO(fmt, ...) log_test_info("INFO", fmt, ##__VA_ARGS__)
#define LOG_WARN(fmt, ...) log_test_info("WARN", fmt, ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) log_test_info("ERROR", fmt, ##__VA_ARGS__)
#define LOG_DEBUG(fmt, ...) log_test_info("DEBUG", fmt, ##__VA_ARGS__)

/* 测试环境管理 */
int init_test_environment(int node_count);
void cleanup_test_environment(void);

/* 节点控制 */
int start_node(int node_id);
void stop_node(int node_id);
void crash_node(int node_id);
void recover_node(int node_id);

/* 网络模拟 */
int network_simulator_init(network_simulator_t* net, int node_count);
void network_simulator_cleanup(network_simulator_t* net);
bool network_can_send_message(network_simulator_t* net, int from, int to);
void network_simulate_partition(network_simulator_t* net, 
                               int* group1, int group1_size,
                               int* group2, int group2_size);
void network_heal_partition(network_simulator_t* net, int node_count);

/* 集群状态检查 */
int get_cluster_leader(void);
bool wait_for_leader_election(int timeout_ms);
bool check_log_consistency(void);

#endif /* XDEVICE_TEST_HELPERS_H */

/* ========== Helper Function Implementations ========== */

double get_current_time_ms(void) {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec * 1000.0 + ts.tv_nsec / 1000000.0;
}

void sleep_ms(int ms) {
    usleep(ms * 1000);
}

void log_test_info(const char* level, const char* format, ...) {
    va_list args;
    char timestamp[32];
    time_t now = time(NULL);
    strftime(timestamp, sizeof(timestamp), "%H:%M:%S", localtime(&now));
    
    printf("[%s %s] ", timestamp, level);
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
    printf("\\n");
    fflush(stdout);
}

int network_simulator_init(network_simulator_t* net, int node_count) {
    pthread_mutex_init(&net->lock, NULL);
    
    for (int i = 0; i < node_count; i++) {
        for (int j = 0; j < node_count; j++) {
            net->connected[i][j] = (i != j);
            net->message_delay_ms[i][j] = 1 + (rand() % 5);
            net->packet_loss_rate[i][j] = 0.0;
        }
    }
    
    LOG_INFO("网络模拟器初始化完成，%d个节点", node_count);
    return 0;
}

void network_simulator_cleanup(network_simulator_t* net) {
    pthread_mutex_destroy(&net->lock);
}

bool network_can_send_message(network_simulator_t* net, int from, int to) {
    pthread_mutex_lock(&net->lock);
    bool can_send = net->connected[from][to];
    
    if (can_send && net->packet_loss_rate[from][to] > 0) {
        double rand_val = (double)rand() / RAND_MAX;
        if (rand_val < net->packet_loss_rate[from][to]) {
            can_send = false;
        }
    }
    
    pthread_mutex_unlock(&net->lock);
    return can_send;
}

void network_simulate_partition(network_simulator_t* net, 
                               int* group1, int group1_size,
                               int* group2, int group2_size) {
    pthread_mutex_lock(&net->lock);
    
    for (int i = 0; i < group1_size; i++) {
        for (int j = 0; j < group2_size; j++) {
            net->connected[group1[i]][group2[j]] = false;
            net->connected[group2[j]][group1[i]] = false;
        }
    }
    
    LOG_WARN("模拟网络分区：组1(%d节点) vs 组2(%d节点)", group1_size, group2_size);
    pthread_mutex_unlock(&net->lock);
}

void network_heal_partition(network_simulator_t* net, int node_count) {
    pthread_mutex_lock(&net->lock);
    
    for (int i = 0; i < node_count; i++) {
        for (int j = 0; j < node_count; j++) {
            if (i != j) {
                net->connected[i][j] = true;
            }
        }
    }
    
    LOG_INFO("恢复网络连通性");
    pthread_mutex_unlock(&net->lock);
}

int init_test_environment(int node_count) {
    if (node_count > MAX_TEST_NODES || node_count < 1) {
        LOG_ERROR("节点数量无效: %d (应在1-%d之间)", node_count, MAX_TEST_NODES);
        return -1;
    }
    
    memset(&g_test_env, 0, sizeof(g_test_env));
    g_test_env.node_count = node_count;
    g_test_env.test_running = true;
    g_test_env.current_leader = -1;
    g_test_env.global_term = 0;
    g_test_env.start_time = get_current_time_ms();
    
    pthread_mutex_init(&g_test_env.env_lock, NULL);
    pthread_cond_init(&g_test_env.state_changed, NULL);
    
    if (network_simulator_init(&g_test_env.network, node_count) != 0) {
        LOG_ERROR("网络模拟器初始化失败");
        return -1;
    }
    
    LOG_INFO("初始化测试环境，节点数量: %d", node_count);
    
    for (int i = 0; i < node_count; i++) {
        test_node_t* node = &g_test_env.nodes[i];
        node->node_id = i;
        node->running = false;
        node->crashed = false;
        node->isolated = false;
        node->current_term = 0;
        node->voted_for = -1;
        node->state = XDEVICE_NODE_UNKNOWN;
        node->commit_index = 0;
        node->last_applied = 0;
        
        pthread_mutex_init(&node->lock, NULL);
        
        char data_dir[512];
        snprintf(data_dir, sizeof(data_dir), "/tmp/xdevice_raft_test_node_%d_%ld", 
                 i, (long)time(NULL));
        
        char cmd[1024];
        snprintf(cmd, sizeof(cmd), "rm -rf %s && mkdir -p %s", data_dir, data_dir);
        if (system(cmd) != 0) {
            LOG_ERROR("创建数据目录失败: %s", data_dir);
            return -1;
        }
        
        node->ctx = xdevice_init(data_dir, i, node_count);
        if (!node->ctx) {
            LOG_ERROR("节点 %d 初始化失败", i);
            return -1;
        }
        
        LOG_DEBUG("节点 %d 初始化成功，数据目录: %s", i, data_dir);
    }
    
    return 0;
}

void cleanup_test_environment(void) {
    LOG_INFO("清理测试环境");
    
    g_test_env.test_running = false;
    pthread_cond_broadcast(&g_test_env.state_changed);
    
    for (int i = 0; i < g_test_env.node_count; i++) {
        test_node_t* node = &g_test_env.nodes[i];
        
        if (node->running) {
            node->running = false;
            // Note: pthread_join would be called by the test file
        }
        
        if (node->ctx) {
            xdevice_destroy(node->ctx);
        }
        
        pthread_mutex_destroy(&node->lock);
        
        char cmd[512];
        snprintf(cmd, sizeof(cmd), "rm -rf /tmp/xdevice_raft_test_node_%d_*", i);
        int result = system(cmd);
        (void)result; // Suppress unused result warning
    }
    
    network_simulator_cleanup(&g_test_env.network);
    pthread_mutex_destroy(&g_test_env.env_lock);
    pthread_cond_destroy(&g_test_env.state_changed);
    
    LOG_INFO("测试环境清理完成");
}

static void* node_worker_thread(void* arg) {
    test_node_t* node = (test_node_t*)arg;
    LOG_DEBUG("节点 %d 工作线程启动", node->node_id);
    
    while (node->running && g_test_env.test_running) {
        pthread_mutex_lock(&node->lock);
        
        if (!node->crashed && !node->isolated) {
            if (node->state == XDEVICE_NODE_LEADER) {
                raft_cluster_send_heartbeat();
                node->messages_sent++;
            }
            
            if (node->state == XDEVICE_NODE_FOLLOWER || 
                node->state == XDEVICE_NODE_CANDIDATE) {
                if (raft_cluster_should_start_election()) {
                    raft_cluster_start_election();
                    node->elections_started++;
                }
            }
            
            node->current_term = raft_cluster_get_term();
            node->state = raft_cluster_get_node_state();
        }
        
        pthread_mutex_unlock(&node->lock);
        sleep_ms(HEARTBEAT_INTERVAL_MS);
    }
    
    LOG_DEBUG("节点 %d 工作线程结束", node->node_id);
    return NULL;
}

int start_node(int node_id) {
    if (node_id >= g_test_env.node_count) {
        return -1;
    }
    
    test_node_t* node = &g_test_env.nodes[node_id];
    
    if (raft_cluster_init(node_id, g_test_env.node_count) != 0) {
        LOG_ERROR("节点 %d Raft集群初始化失败", node_id);
        return -1;
    }
    
    if (raft_node_init(node_id) != 0) {
        LOG_ERROR("节点 %d Raft节点初始化失败", node_id);
        return -1;
    }
    
    if (raft_log_init() != 0) {
        LOG_ERROR("节点 %d Raft日志初始化失败", node_id);
        return -1;
    }
    
    node->running = true;
    node->crashed = false;
    
    if (pthread_create(&node->worker_thread, NULL, node_worker_thread, node) != 0) {
        LOG_ERROR("节点 %d 工作线程创建失败", node_id);
        return -1;
    }
    
    LOG_INFO("节点 %d 启动成功", node_id);
    return 0;
}

void stop_node(int node_id) {
    if (node_id >= g_test_env.node_count) {
        return;
    }
    
    test_node_t* node = &g_test_env.nodes[node_id];
    node->running = false;
    
    if (pthread_join(node->worker_thread, NULL) == 0) {
        LOG_INFO("节点 %d 停止成功", node_id);
    }
}

void crash_node(int node_id) {
    if (node_id >= g_test_env.node_count) {
        return;
    }
    
    pthread_mutex_lock(&g_test_env.nodes[node_id].lock);
    g_test_env.nodes[node_id].crashed = true;
    pthread_mutex_unlock(&g_test_env.nodes[node_id].lock);
    
    LOG_WARN("节点 %d 模拟崩溃", node_id);
}

void recover_node(int node_id) {
    if (node_id >= g_test_env.node_count) {
        return;
    }
    
    pthread_mutex_lock(&g_test_env.nodes[node_id].lock);
    g_test_env.nodes[node_id].crashed = false;
    pthread_mutex_unlock(&g_test_env.nodes[node_id].lock);
    
    LOG_INFO("节点 %d 从崩溃恢复", node_id);
}

int get_cluster_leader(void) {
    int leader_count = 0;
    int leader_id = -1;
    
    for (int i = 0; i < g_test_env.node_count; i++) {
        test_node_t* node = &g_test_env.nodes[i];
        
        pthread_mutex_lock(&node->lock);
        if (!node->crashed && !node->isolated && 
            node->state == XDEVICE_NODE_LEADER) {
            leader_count++;
            leader_id = i;
        }
        pthread_mutex_unlock(&node->lock);
    }
    
    if (leader_count == 0) {
        return -1;  // 无领导者
    } else if (leader_count == 1) {
        return leader_id;  // 正常情况
    } else {
        return -2;  // Split-brain：多个领导者
    }
}

bool wait_for_leader_election(int timeout_ms) {
    double start_time = get_current_time_ms();
    int leader_id = -1;
    
    LOG_INFO("等待领导者选举...");
    
    while ((get_current_time_ms() - start_time) < timeout_ms) {
        leader_id = get_cluster_leader();
        
        if (leader_id >= 0) {
            LOG_INFO("领导者选出: 节点 %d", leader_id);
            g_test_env.current_leader = leader_id;
            g_test_env.leader_changes++;
            return true;
        }
        
        if (leader_id == -2) {
            LOG_ERROR("检测到Split-brain：多个领导者同时存在！");
            return false;
        }
        
        sleep_ms(50);
    }
    
    LOG_WARN("领导者选举超时");
    return false;
}

bool check_log_consistency(void) {
    if (g_test_env.node_count == 0) {
        return true;
    }
    
    test_node_t* reference_node = NULL;
    for (int i = 0; i < g_test_env.node_count; i++) {
        if (!g_test_env.nodes[i].crashed) {
            reference_node = &g_test_env.nodes[i];
            break;
        }
    }
    
    if (!reference_node) {
        return true;  // All nodes crashed
    }
    
    uint64_t ref_last_index = raft_log_get_last_index();
    uint64_t ref_commit_index = raft_log_get_commit_index();
    (void)ref_last_index; // May be used in future enhancements
    
    for (int i = 0; i < g_test_env.node_count; i++) {
        test_node_t* node = &g_test_env.nodes[i];
        
        if (node->crashed || node == reference_node) {
            continue;
        }
        
        uint64_t node_last_index = raft_log_get_last_index();
        uint64_t node_commit_index = raft_log_get_commit_index();
        (void)node_last_index; // May be used in future enhancements
        
        for (uint64_t idx = 1; idx <= node_commit_index && idx <= ref_commit_index; idx++) {
            char ref_data[1024], node_data[1024];
            size_t ref_size = sizeof(ref_data), node_size = sizeof(node_data);
            uint64_t ref_term, node_term;
            
            if (raft_log_get_entry(idx, ref_data, &ref_size, &ref_term) == 0 &&
                raft_log_get_entry(idx, node_data, &node_size, &node_term) == 0) {
                
                if (ref_term != node_term || ref_size != node_size ||
                    memcmp(ref_data, node_data, ref_size) != 0) {
                    LOG_ERROR("日志不一致：节点 %d vs 参考节点 %d，索引 %lu", 
                             node->node_id, reference_node->node_id, idx);
                    return false;
                }
            }
        }
    }
    
    return true;
}
